home *** CD-ROM | disk | FTP | other *** search
/ NeXT Education Software Sampler 1992 Fall / NeXT Education Software Sampler 1992 Fall.iso / Programming / Source / winterp-1.13 / src-server / w_callbacks.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-10-04  |  26.9 KB  |  725 lines

  1. /* -*-C-*-
  2. ********************************************************************************
  3. *
  4. * File:         w_callbacks.c
  5. * RCS:          $Header: w_callbacks.c,v 1.9 91/03/14 03:13:25 mayer Exp $
  6. * Description:  
  7. * Author:       Niels Mayer, HPLabs
  8. * Created:      Sat Aug 26 07:44:17 1989
  9. * Modified:     Thu Oct  3 21:32:41 1991 (Niels Mayer) mayer@hplnpm
  10. * Language:     C
  11. * Package:      N/A
  12. * Status:       X11r5 contrib tape release
  13. *
  14. * WINTERP Copyright 1989, 1990, 1991 Hewlett-Packard Company (by Niels Mayer).
  15. * XLISP version 2.1, Copyright (c) 1989, by David Betz.
  16. *
  17. * Permission to use, copy, modify, distribute, and sell this software and its
  18. * documentation for any purpose is hereby granted without fee, provided that
  19. * the above copyright notice appear in all copies and that both that
  20. * copyright notice and this permission notice appear in supporting
  21. * documentation, and that the name of Hewlett-Packard and David Betz not be
  22. * used in advertising or publicity pertaining to distribution of the software
  23. * without specific, written prior permission.  Hewlett-Packard and David Betz
  24. * make no representations about the suitability of this software for any
  25. * purpose. It is provided "as is" without express or implied warranty.
  26. *
  27. * HEWLETT-PACKARD AND DAVID BETZ DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
  28. * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
  29. * IN NO EVENT SHALL HEWLETT-PACKARD NOR DAVID BETZ BE LIABLE FOR ANY SPECIAL,
  30. * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  31. * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  32. * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  33. * PERFORMANCE OF THIS SOFTWARE.
  34. *
  35. * See ./winterp/COPYRIGHT for information on contacting the authors.
  36. * Please send modifications, improvements and bugfixes to mayer@hplabs.hp.com
  37. * Post XLISP-specific questions/information to the newsgroup comp.lang.lisp.x
  38. *
  39. ********************************************************************************
  40. */
  41. static char rcs_identity[] = "@(#)$Header: w_callbacks.c,v 1.9 91/03/14 03:13:25 mayer Exp $";
  42.  
  43. #include <stdio.h>
  44. #include <Xm/Xm.h>
  45. #include "winterp.h"
  46. #include "user_prefs.h"
  47. #include "xlisp/xlisp.h"
  48.  
  49. #ifdef HP_GRAPH_WIDGET
  50. #include <Xm/Graph.h>        /* needed for graph widget's added callback reasins XmCR_* */
  51. #endif                /* HP_GRAPH_WIDGET */
  52.  
  53. /* Symbols init'd in Wcb_Init() */
  54. LVAL s_CALLBACK_WIDGET, s_CALLBACK_REASON, s_CALLBACK_XEVENT, s_CALLBACK_WINDOW, s_CALLBACK_VALUE, s_CALLBACK_LENGTH;
  55. #ifdef WINTERP_MOTIF_11
  56. LVAL s_CALLBACK_CLICK_COUNT;
  57. #endif                /* WINTERP_MOTIF_11 */
  58.  
  59.  
  60. /* 
  61.  * To prevent garbage collection of callback-objects, we store the objects in
  62.  * the hashtable w_savedobjs.c:v_savedobjs after hashing on the address of the
  63.  * widget-object LVAL. Since callbacks occur on a per-widget basis, we use the
  64.  * widget as the hash-key and then search through the hashbucket looking for
  65.  * LVALs that are callback-objects, have the appropriate widget-object, and
  66.  * have the right callback name.
  67.  * 
  68.  * Garbage collection of lisp-objects will occur to any object not referenced
  69.  * as symbol values, inside lexical environments saved as functional closures,
  70.  * as elements of the evaluation or argument stack. In the case of callbacks,
  71.  * the callback closure, the callback's lexical environment, and the callback
  72.  * widget are implicitly referenced inside Motif/Xtoolkit code. As long as the
  73.  * widget on which these callbacks are placed still exists, we must prevent
  74.  * callback-objects from being garbage collected. 
  75.  * 
  76.  * This is done by:
  77.  *    1) storing them in v_savedobjs when the callback is added
  78.  *       (note that v_savedobjs is a hashtable hashed by the LVAL's pointer,
  79.  *        for callbacks, we store all callbacks on a particular widget in the
  80.  *        hashbucket associated with hashing on that widget-object. this makes
  81.  *        it easier to implement :set_callback. and :remove_all_callbacks.)
  82.  *    2) removing them when the callback is removed
  83.  *       (as in methods :set_callback :remove_all_callbacks and function remove_callback)
  84.  *    3) removing them when the widget is destroyed.
  85.  *       (requires a destroy callback to be added onto each widget)
  86.  */
  87.  
  88.  
  89. /******************************************************************************
  90.  * 
  91.  ******************************************************************************/
  92. void Wcb_Meta_Callbackproc(client_data, call_data, bind_call_data_values_proc, set_call_data_values_proc)
  93.      XtPointer client_data;    /* XLTYPE_CALLBACKOBJ */
  94.      XtPointer call_data;    /* a pointer to a structure that is accessed via (*bind_call_data_values_proc)() */
  95.      void      (*bind_call_data_values_proc)(/* LVAL bindings_list; LVAL lexical_env; XtPointer call_data; LVAL o_widget */);
  96.      void      (*set_call_data_values_proc)(/* LVAL bindings_list; LVAL lexical_env; XtPointer call_data */);
  97. {
  98.   extern LVAL          xlenv, xlfenv;
  99.   LVAL                 oldenv, oldfenv, l_evalforms, s_name;
  100.   CONTEXT              cntxt;
  101.   LVAL                 c_callback = get_callback_closure((LVAL) client_data);
  102.  
  103.   /*
  104.    * Most of this procedure looks alot like xleval.c:evfun(), which is what
  105.    * the evaluator calls when a functional form is to be evaluated. The
  106.    * main difference is that instead of calling xlabind() to bind the
  107.    * formal parameter symbols of a function to their values in the new
  108.    * lexical environment frame returned by xlframe(getenv(fun)), we look
  109.    * at the formal args from the callback's closure and bind these to the
  110.    * appropriate values.
  111.    */
  112.   
  113.   /* protect some pointers */
  114.   xlstkcheck(3);
  115.   xlsave(oldenv);
  116.   xlsave(oldfenv);
  117.   xlsave(l_evalforms);
  118.   
  119.   /* create a new environment frame */
  120.   oldenv = xlenv;
  121.   oldfenv = xlfenv;
  122.   xlenv = xlframe(getenvt(c_callback));    /* note: changed getenv()-->getenvt() due to name conflict with stdlib.h:getenv() */
  123.   xlfenv = getfenv(c_callback);
  124.   
  125.   /* get the list of bindings and bind (locally) the symbols to values retrieved from call_data -- see also xlabind() */
  126.   (*bind_call_data_values_proc)(getargs(c_callback), /* a list of symbols to which values from call_data struct are locally bound */
  127.                 xlenv, /* the lexical environment in which the bindings are made  */
  128.                 call_data, /* a pointer to a Xm*CallbackStruct (the structure used depends on the widget-class of the widget containing the callback */
  129.                 get_callback_widget((LVAL) client_data)); /* the WIDGETOBJ on which the callback occured. */
  130.   
  131.   /* setup the implicit block */
  132.   if (s_name = getname(c_callback))
  133.     xlbegin(&cntxt, CF_RETURN, s_name);
  134.   
  135.   /* execute the block */
  136.   if (s_name && setjmp(cntxt.c_jmpbuf))
  137.     { }
  138.   else
  139.     for (l_evalforms = getbody(c_callback); consp(l_evalforms); 
  140.      l_evalforms = cdr(l_evalforms))
  141.       xleval(car(l_evalforms));
  142.  
  143.   /* if this is a callback in which elements of the call_data structure must
  144.      be set before the callback returns (as in the XmText or the XmGraph widgets),
  145.      then set_call_data_values_proc is a pointer to the function that does this
  146.      dirty deed. */
  147.   if (set_call_data_values_proc)
  148.     (*set_call_data_values_proc)(getargs(c_callback), /* a list of symbols to which values from call_data struct are locally bound */
  149.                  xlenv, /* the lexical environment in which the bindings are made  */
  150.                  call_data); /* a pointer to a Xm*CallbackStruct (the structure used depends on the widget-class of the widget containing the callback */
  151.   
  152.   /* finish the block context */
  153.   if (s_name)
  154.     xlend(&cntxt);
  155.   
  156.   /* restore the environment */
  157.   xlenv = oldenv;
  158.   xlfenv = oldfenv;
  159.   
  160.   /* restore the stack */
  161.   xlpopn(3);
  162. }
  163.  
  164. /******************************************************************************
  165.  * Are we having fun yet?
  166.  ******************************************************************************/
  167. static LVAL s_CR_NONE, s_CR_HELP, s_CR_VALUE_CHANGED, s_CR_INCREMENT, /* Symbols init'd in Wcb_Init() */
  168.   s_CR_DECREMENT, s_CR_PAGE_INCREMENT, s_CR_PAGE_DECREMENT, s_CR_TO_TOP,
  169.   s_CR_TO_BOTTOM, s_CR_DRAG, s_CR_ACTIVATE, s_CR_ARM, s_CR_DISARM, s_CR_MAP,
  170.   s_CR_UNMAP, s_CR_FOCUS, s_CR_LOSING_FOCUS, s_CR_MODIFYING_TEXT_VALUE,
  171.   s_CR_MOVING_INSERT_CURSOR, s_CR_EXECUTE, s_CR_SINGLE_SELECT,
  172.   s_CR_MULTIPLE_SELECT, s_CR_EXTENDED_SELECT, s_CR_BROWSE_SELECT,
  173.   s_CR_DEFAULT_ACTION, s_CR_CLIPBOARD_DATA_REQUEST, s_CR_CLIPBOARD_DATA_DELETE,
  174.   s_CR_CASCADING, s_CR_OK, s_CR_CANCEL, s_CR_APPLY, s_CR_NO_MATCH,
  175.   s_CR_COMMAND_ENTERED, s_CR_COMMAND_CHANGED, s_CR_EXPOSE, s_CR_RESIZE, s_CR_INPUT;
  176. #ifdef WINTERP_MOTIF_11
  177. static LVAL s_CR_GAIN_PRIMARY, s_CR_LOSE_PRIMARY;
  178. #ifdef XmCR_CREATE        /* added in Motif 1.1.3 */
  179. static LVAL s_XmCR_CREATE;
  180. #endif /* XmCR_CREATE */
  181. #ifdef XmCR_PROTOCOLS        /* added in Motif 1.1.3 */
  182. static LVAL s_XmCR_PROTOCOLS;
  183. #endif /* XmCR_PROTOCOLS */
  184. #endif                /* WINTERP_MOTIF_11 */
  185.  
  186. #ifdef HP_GRAPH_WIDGET
  187. static LVAL s_CR_NEW_ARC, s_CR_NEW_NODE, s_CR_NODE_MOVED, s_CR_ARC_MOVED, s_CR_SUBGRAPH_MOVED, /* Symbols init'd in Wcb_Init() */
  188.   s_CR_ARC_EDITED, s_CR_SELECT_NODE, s_CR_SELECT_ARC, s_CR_SELECT_SUBGRAPH, s_CR_DELETE_NODE,
  189.   s_CR_DELETE_ARC, s_CR_SELECT, s_CR_RELEASE, s_CR_NODE_DOUBLE_CLICK, s_CR_ARC_DOUBLE_CLICK,
  190.   s_CR_DOUBLE_CLICK, s_CR_DESELECT_ARC, s_CR_DESELECT_NODE, s_CR_DESELECT;
  191. #endif                /* HP_GRAPH_WIDGET */
  192.  
  193. LVAL Wcb_Get_Callback_Reason_Symbol(cb_reason)
  194.      int cb_reason;
  195. {
  196.   switch (cb_reason) {
  197.   case XmCR_NONE:
  198.     return (s_CR_NONE);
  199.   case XmCR_HELP:
  200.     return (s_CR_HELP);
  201.   case XmCR_VALUE_CHANGED:
  202.     return (s_CR_VALUE_CHANGED);
  203.   case XmCR_INCREMENT:
  204.     return (s_CR_INCREMENT);
  205.   case XmCR_DECREMENT:
  206.     return (s_CR_DECREMENT);
  207.   case XmCR_PAGE_INCREMENT:
  208.     return (s_CR_PAGE_INCREMENT);
  209.   case XmCR_PAGE_DECREMENT:
  210.     return (s_CR_PAGE_DECREMENT);
  211.   case XmCR_TO_TOP:
  212.     return (s_CR_TO_TOP);
  213.   case XmCR_TO_BOTTOM:
  214.     return (s_CR_TO_BOTTOM);
  215.   case XmCR_DRAG:
  216.     return (s_CR_DRAG);
  217.   case XmCR_ACTIVATE:
  218.     return (s_CR_ACTIVATE);
  219.   case XmCR_ARM:
  220.     return (s_CR_ARM);
  221.   case XmCR_DISARM:
  222.     return (s_CR_DISARM);
  223.   case XmCR_MAP:
  224.     return (s_CR_MAP);
  225.   case XmCR_UNMAP:
  226.     return (s_CR_UNMAP);
  227.   case XmCR_FOCUS:
  228.     return (s_CR_FOCUS);
  229.   case XmCR_LOSING_FOCUS:
  230.     return (s_CR_LOSING_FOCUS);
  231.   case XmCR_MODIFYING_TEXT_VALUE:
  232.     return (s_CR_MODIFYING_TEXT_VALUE);
  233.   case XmCR_MOVING_INSERT_CURSOR:
  234.     return (s_CR_MOVING_INSERT_CURSOR);
  235.   case XmCR_EXECUTE:
  236.     return (s_CR_EXECUTE);
  237.   case XmCR_SINGLE_SELECT:
  238.     return (s_CR_SINGLE_SELECT);
  239.   case XmCR_MULTIPLE_SELECT:
  240.     return (s_CR_MULTIPLE_SELECT);
  241.   case XmCR_EXTENDED_SELECT:
  242.     return (s_CR_EXTENDED_SELECT);
  243.   case XmCR_BROWSE_SELECT:
  244.     return (s_CR_BROWSE_SELECT);
  245.   case XmCR_DEFAULT_ACTION:
  246.     return (s_CR_DEFAULT_ACTION);
  247.   case XmCR_CLIPBOARD_DATA_REQUEST:
  248.     return (s_CR_CLIPBOARD_DATA_REQUEST);
  249.   case XmCR_CLIPBOARD_DATA_DELETE:
  250.     return (s_CR_CLIPBOARD_DATA_DELETE);
  251.   case XmCR_CASCADING:
  252.     return (s_CR_CASCADING);
  253.   case XmCR_OK:
  254.     return (s_CR_OK);
  255.   case XmCR_CANCEL:
  256.     return (s_CR_CANCEL);
  257.   case XmCR_APPLY:
  258.     return (s_CR_APPLY);
  259.   case XmCR_NO_MATCH:
  260.     return (s_CR_NO_MATCH);
  261.   case XmCR_COMMAND_ENTERED:
  262.     return (s_CR_COMMAND_ENTERED);
  263.   case XmCR_COMMAND_CHANGED:
  264.     return (s_CR_COMMAND_CHANGED);
  265.   case XmCR_EXPOSE:
  266.     return (s_CR_EXPOSE);
  267.   case XmCR_RESIZE:
  268.     return (s_CR_RESIZE);
  269.   case XmCR_INPUT:
  270.     return (s_CR_INPUT);
  271. #ifdef WINTERP_MOTIF_11
  272.   case XmCR_GAIN_PRIMARY:
  273.     return (s_CR_GAIN_PRIMARY);
  274.   case XmCR_LOSE_PRIMARY:
  275.     return (s_CR_LOSE_PRIMARY);
  276. #ifdef XmCR_CREATE        /* added in Motif 1.1.3 */
  277.   case XmCR_CREATE:
  278.     return (s_XmCR_CREATE);
  279. #endif /* XmCR_CREATE */
  280. #ifdef XmCR_PROTOCOLS        /* added in Motif 1.1.3 */
  281.   case XmCR_PROTOCOLS:
  282.     return (s_XmCR_PROTOCOLS);
  283. #endif /* XmCR_PROTOCOLS */
  284. #endif /* WINTERP_MOTIF_11 */
  285.  
  286. #ifdef HP_GRAPH_WIDGET
  287.   case XmCR_NEW_ARC:
  288.     return (s_CR_NEW_ARC);
  289.   case XmCR_NEW_NODE:
  290.     return (s_CR_NEW_NODE);
  291.   case XmCR_NODE_MOVED:
  292.     return (s_CR_NODE_MOVED);
  293.   case XmCR_ARC_MOVED:
  294.     return (s_CR_ARC_MOVED);
  295.   case XmCR_SUBGRAPH_MOVED:
  296.     return (s_CR_SUBGRAPH_MOVED);
  297.   case XmCR_ARC_EDITED:
  298.     return (s_CR_ARC_EDITED);
  299.   case XmCR_SELECT_NODE:
  300.     return (s_CR_SELECT_NODE);
  301.   case XmCR_SELECT_ARC:
  302.     return (s_CR_SELECT_ARC);
  303.   case XmCR_SELECT_SUBGRAPH:
  304.     return (s_CR_SELECT_SUBGRAPH);
  305.   case XmCR_DELETE_NODE:
  306.     return (s_CR_DELETE_NODE);
  307.   case XmCR_DELETE_ARC:
  308.     return (s_CR_DELETE_ARC);
  309.   case XmCR_SELECT:
  310.     return (s_CR_SELECT);
  311.   case XmCR_RELEASE:
  312.     return (s_CR_RELEASE);
  313.   case XmCR_NODE_DOUBLE_CLICK:
  314.     return (s_CR_NODE_DOUBLE_CLICK);
  315.   case XmCR_ARC_DOUBLE_CLICK:
  316.     return (s_CR_ARC_DOUBLE_CLICK);
  317.   case XmCR_DOUBLE_CLICK:
  318.     return (s_CR_DOUBLE_CLICK);
  319.   case XmCR_DESELECT_ARC:
  320.     return (s_CR_DESELECT_ARC);
  321.   case XmCR_DESELECT_NODE:
  322.     return (s_CR_DESELECT_NODE);
  323.   case XmCR_DESELECT:
  324.     return (s_CR_DESELECT);
  325. #endif /* HP_GRAPH_WIDGET */
  326.  
  327.   default:
  328.     xlfail("Internal error in Wcb_Get_Callback_Reason_Symbol() -- unknown callback reason.");
  329.   }
  330. }
  331.  
  332.  
  333. /*******************************************************************************
  334.  *
  335.  ******************************************************************************/
  336. LVAL Wcb_Meta_Method_Add_Callback(callback_proc, one_callback_per_name_p)
  337.      XtCallbackProc callback_proc;
  338.      Boolean        one_callback_per_name_p;
  339. {
  340.   extern Widget Wcls_Get_WIDGETOBJ_Argument_Returning_Validated_WidgetID(); /* w_classes.c */
  341.   extern char* Wres_Get_Name();    /* w_resources.c */
  342.   extern LVAL  Wres_Get_Symbol(); /* w_resources.c */
  343.   extern Boolean Wres_Is_Callback_P(); /* w_resources.c */
  344.   extern LVAL s_lambda, xlenv, xlfenv;
  345.   LVAL   o_self, l_fargs, l_code;
  346.   LVAL   xtr_name, s_callback, callback_obj;
  347.   Widget widget_id;
  348.   char*  name;
  349.   
  350.   /* get <widget_instance> */
  351.   widget_id = Wcls_Get_WIDGETOBJ_Argument_Returning_Validated_WidgetID(&o_self);
  352.                     
  353.   /* get <name> */
  354.   xtr_name = xlgetarg();
  355.   if (xtresource_p(xtr_name) && Wres_Is_Callback_P(xtr_name)) {
  356.     name = Wres_Get_Name(xtr_name);
  357.     s_callback = Wres_Get_Symbol(xtr_name);
  358.   }
  359.   else if (symbolp(xtr_name)) {    
  360.     xtr_name = getvalue(xtr_name);
  361.     if (xtresource_p(xtr_name) && Wres_Is_Callback_P(xtr_name)) {
  362.       name = Wres_Get_Name(xtr_name);
  363.       s_callback = Wres_Get_Symbol(xtr_name);
  364.     }
  365.     else
  366.       xlerror("Invalid callback name symbol", xtr_name);
  367.   }
  368.   else
  369.     xlerror("Invalid callback name argument", xtr_name);
  370.       
  371.   /* get <call_data_binding_names_list> -- args to be bound at call time.
  372.      NOTE: may want to check that these args are valid for the particular widget
  373.      class that this "meta-method" is used in. No biggie though -- they'll get
  374.      caught at runtime, when the callback fires. */
  375.   l_fargs = xlgalist();        
  376.  
  377.   /* get <code> */
  378.   l_code = xlgalist();
  379.   xllastarg();
  380.  
  381.   /* 
  382.    * if this procedure is being called from the :set_callback method 
  383.    * (indicated by one_callback_per_name_p = TRUE), 
  384.    * then remove all callbacks on <widget_inst> matching <name>
  385.    */
  386.   if (one_callback_per_name_p) { 
  387.     extern LVAL v_savedobjs;    
  388.     int  i = Wso_Hash(o_self);
  389.     LVAL l_hbucket = getelement(v_savedobjs, i); /* a list of objects, including all callback-objs on this widget */
  390.     LVAL obj;
  391.     LVAL l_prev = NIL;
  392.     while (l_hbucket) {        /* while there are elements in the hashbucket */
  393.       obj = car(l_hbucket);    /* obj points to cur elt */
  394.       if (callbackobj_p(obj) && (get_callback_name(obj) == name) && (get_callback_widget(obj) == o_self)) {
  395.     XtRemoveCallback(widget_id, name, get_callback_proc(obj), (XtPointer) obj);
  396.     l_hbucket = cdr(l_hbucket); /* l_hbucket now points to next elt or NIL */
  397.     if (!l_prev)
  398.       setelement(v_savedobjs, i, l_hbucket); /* remove first, head is now next elt */
  399.     else
  400.       rplacd(l_prev, l_hbucket); /* remove cur, point previous to next */
  401.       }
  402.       else {
  403.     l_prev = l_hbucket;
  404.     l_hbucket = cdr(l_hbucket);
  405.       }
  406.     }
  407.   }
  408.  
  409.   /* 
  410.    * create the client_data to be sent to (*callback_proc)()
  411.    * That procedure takes the client_data and extracts the widget-object,
  412.    * and the closure, and uses these to execute the callback.
  413.    */
  414.   xlsave1(callback_obj);    /* protect some pointers */
  415.   callback_obj = new_callbackobj();
  416.   set_callback_widget(callback_obj, o_self);
  417.   set_callback_name(callback_obj, name);
  418.   set_callback_proc(callback_obj, callback_proc);
  419.   set_callback_closure(callback_obj,
  420.                xlclose(s_callback, s_lambda, l_fargs, l_code, xlenv, xlfenv));
  421.   
  422.   XtAddCallback(widget_id, name, callback_proc, (XtPointer) callback_obj);
  423.  
  424.   /*
  425.    * Enter the callback_obj in v_savedobjs, so that it gets marked.
  426.    * This way, it won't be garbage collected while the callback is
  427.    * active. :set_callback, xt_remove_callback, and :remove_all_callbacks
  428.    * may remove and destroy the callback_obj created here. Destroying the
  429.    * widget will result in the callbackobj getting garbage collected 
  430.    * -- see Wcls_Widget_Destroy_Callback()
  431.    */
  432.   { 
  433.     int  i = Wso_Hash(o_self);
  434.     LVAL l_hbucket;
  435.     extern LVAL v_savedobjs;
  436.     
  437.     xlsave1(l_hbucket);
  438.     l_hbucket = cons(callback_obj, getelement(v_savedobjs, i));
  439.     setelement(v_savedobjs, i, l_hbucket);
  440.     xlpop();
  441.   }
  442.  
  443.   /* resore the stack */
  444.   xlpop(/*callback_obj*/);
  445.  
  446.   return (callback_obj);
  447. }
  448.  
  449.  
  450. /******************************************************************************
  451.  * lisp: (SEND <widget> :REMOVE_ALL_CALLBACKS <name>)
  452.  * returns T.
  453.  *
  454.  * <name> is a resource keyword of type XmRCallback, eg,
  455.  * :XMN_ACTIVATE_CALLBACK, :XMN_ARM_CALLBACK, :XMN_DISARM_CALLBACK.
  456.  *
  457.  * This procedure removes all callbacks matching <name> for <widget>.
  458.  ******************************************************************************/
  459. LVAL Widget_Class_Method_REMOVE_ALL_CALLBACKS()
  460. {
  461.   extern Widget Wcls_Get_WIDGETOBJ_Argument_Returning_Validated_WidgetID(); /* w_classes.c */
  462.   extern char* Wres_Get_Name();    /* w_resources.c */
  463.   extern Boolean Wres_Is_Callback_P(); /* w_resources.c */
  464.   LVAL   o_self;
  465.   LVAL   xtr_name;
  466.   Widget widget_id;
  467.   char*  name;
  468.   
  469.   /* get <widget_instance> */
  470.   widget_id = Wcls_Get_WIDGETOBJ_Argument_Returning_Validated_WidgetID(&o_self);
  471.                     
  472.   /* get <name> */
  473.   xtr_name = xlgetarg();
  474.   if (xtresource_p(xtr_name) && Wres_Is_Callback_P(xtr_name)) {
  475.     name = Wres_Get_Name(xtr_name);
  476.   }
  477.   else if (symbolp(xtr_name)) {    
  478.     xtr_name = getvalue(xtr_name);
  479.     if (xtresource_p(xtr_name) && Wres_Is_Callback_P(xtr_name)) {
  480.       name = Wres_Get_Name(xtr_name);
  481.     }
  482.     else
  483.       xlerror("Invalid callback name symbol", xtr_name);
  484.   }
  485.   else
  486.     xlerror("Invalid callback name argument", xtr_name);
  487.       
  488.   xllastarg();
  489.  
  490.   /* remove from v_savedobjs all callback-objs on <widget_inst> matching <name> */
  491.   {
  492.     extern LVAL v_savedobjs;
  493.     int  i = Wso_Hash(o_self);
  494.     LVAL l_hbucket = getelement(v_savedobjs, i); /* a list of objects, including all callback-objs on this widget  */
  495.     LVAL obj;
  496.     LVAL l_prev = NIL;
  497.     while (l_hbucket) {        /* while there are elements in the hashbucket */
  498.       obj = car(l_hbucket);    /* obj points to cur elt */
  499.       if (callbackobj_p(obj) && (get_callback_name(obj) == name) && (get_callback_widget(obj) == o_self)) {
  500.     l_hbucket = cdr(l_hbucket); /* l_hbucket now points to next elt or NIL */
  501.     if (!l_prev)
  502.       setelement(v_savedobjs, i, l_hbucket); /* remove first, head is now next elt */
  503.     else
  504.       rplacd(l_prev, l_hbucket); /* remove cur, point previous to next */
  505.       }
  506.       else {
  507.     l_prev = l_hbucket;
  508.     l_hbucket = cdr(l_hbucket);
  509.       }
  510.     }
  511.   }
  512.  
  513.   XtRemoveAllCallbacks(widget_id, name);
  514.  
  515.   return (o_self);
  516. }
  517.  
  518.  
  519. /******************************************************************************
  520.  * lisp: (XT_REMOVE_CALLBACK <callback-obj>)
  521.  * 
  522.  * where <callback-obj> is the value returned by methods :set_callback or
  523.  * :add_callback.
  524.  ******************************************************************************/
  525. LVAL Wcb_Prim_XtRemoveCallback()
  526. {
  527.   LVAL callback_obj;
  528.   LVAL o_widget;
  529.   Widget widget_id;
  530.   extern LVAL true;
  531.  
  532.   callback_obj = xlga_callbackobj();
  533.   xllastarg();
  534.  
  535.   /* check if this callback hasn't already been removed */
  536.   if ((o_widget = get_callback_widget(callback_obj)) == NIL)
  537.     xlerror("Callback associated with <callback-obj> has already been removed.", callback_obj);
  538.   
  539.   /* mark the callback_obj as being removed */
  540.   set_callback_widget(callback_obj, NIL);
  541.  
  542.   if (!(widget_id = get_widgetobj_widgetID(o_widget)))
  543.     xlerror("widget object not properly initialized by :isnew.", o_widget);
  544.   
  545.   XtRemoveCallback(widget_id,
  546.            get_callback_name(callback_obj),
  547.            get_callback_proc(callback_obj), /* note that there are difft callbackproc's for difft widgetclasses */
  548.            (XtPointer) callback_obj);
  549.  
  550.   /* remove <callback_obj> from v_savedobjs allowing it to be garbage collected */
  551.   {
  552.     extern LVAL v_savedobjs;
  553.     int i = Wso_Hash(o_widget); /* note that we hash all callbacks on the same widget to the same hashbucket */
  554.     LVAL l_hbucket = getelement(v_savedobjs, i);
  555.     LVAL l_prev = NIL;
  556.  
  557.     while (l_hbucket && (car(l_hbucket) != callback_obj)) {
  558.       l_prev = l_hbucket;
  559.       l_hbucket = cdr(l_hbucket);
  560.     }
  561.     if (!l_hbucket)
  562.       xlerror("Internal error in XtRemoveCallback -- couldn't remove <callback-obj> from v_savedobjs. Hash error?",
  563.           callback_obj);
  564.     if (!l_prev)        /* first elt matched */
  565.       setelement(v_savedobjs, i, cdr(l_hbucket));
  566.     else
  567.       rplacd(l_prev, cdr(l_hbucket));
  568.   }
  569.   
  570.   return (true);
  571. }
  572.  
  573.  
  574. /******************************************************************************
  575.  * lisp: (SEND <widget> :HAS_CALLBACKS <name>)
  576.  *         returns CALLBACK_NO_LIST -- no such callback list
  577.  *        returns CALLBACK_HAS_NONE -- has no callbacks on list
  578.  *        returns CALLBACK_HAS_SOME -- has some callbacks on list
  579.  *
  580.  * <name> is a resource keyword of type XmRCallback, eg,
  581.  * :XMN_ACTIVATE_CALLBACK, :XMN_ARM_CALLBACK, :XMN_DISARM_CALLBACK.
  582.  *
  583.  *
  584.  * XtCallbackStatus XtHasCallbacks(
  585.  *     Widget  widgetm
  586.  *     CONST String callback_name);
  587.  ******************************************************************************/
  588. static LVAL s_CALLBACK_NO_LIST, s_CALLBACK_HAS_NONE, s_CALLBACK_HAS_SOME; /* Symbols init'd in Wcb_Init() */
  589. LVAL Widget_Class_Method_HAS_CALLBACKS()
  590. {
  591.   extern Widget Wcls_Get_WIDGETOBJ_Argument_Returning_Validated_WidgetID(); /* w_classes.c */
  592.   extern char* Wres_Get_Name();    /* w_resources.c */
  593.   extern Boolean Wres_Is_Callback_P(); /* w_resources.c */
  594.   LVAL   o_self;
  595.   LVAL   xtr_name;
  596.   Widget widget_id;
  597.   char*  name;
  598.   
  599.   /* get <widget_instance> */
  600.   widget_id = Wcls_Get_WIDGETOBJ_Argument_Returning_Validated_WidgetID(&o_self);
  601.                     
  602.   /* get <name> */
  603.   xtr_name = xlgetarg();
  604.   if (xtresource_p(xtr_name) && Wres_Is_Callback_P(xtr_name)) {
  605.     name = Wres_Get_Name(xtr_name);
  606.   }
  607.   else if (symbolp(xtr_name)) {    
  608.     xtr_name = getvalue(xtr_name);
  609.     if (xtresource_p(xtr_name) && Wres_Is_Callback_P(xtr_name)) {
  610.       name = Wres_Get_Name(xtr_name);
  611.     }
  612.     else
  613.       xlerror("Invalid callback name symbol", xtr_name);
  614.   }
  615.   else
  616.     xlerror("Invalid callback name argument", xtr_name);
  617.       
  618.   xllastarg();
  619.  
  620.   switch (XtHasCallbacks(widget_id, name)) {
  621.   case XtCallbackNoList:
  622.     return (s_CALLBACK_NO_LIST);
  623.   case XtCallbackHasNone:
  624.     return (s_CALLBACK_HAS_NONE);
  625.   case XtCallbackHasSome:
  626.     return (s_CALLBACK_HAS_SOME);
  627.   }
  628. }
  629.  
  630.  
  631. /******************************************************************************
  632.  *
  633.  ******************************************************************************/
  634. Wcb_Init()
  635. {
  636.   /*
  637.    * Define shared callback call-data symbols used by various
  638.    * Lexical_Bindings_For_Xm*CallbackStruct() procs in noted files.
  639.    */
  640.   s_CALLBACK_WIDGET = xlenter("CALLBACK_WIDGET"); /* wc_*.c */
  641.   s_CALLBACK_REASON = xlenter("CALLBACK_REASON"); /* wc_*.c */
  642.   s_CALLBACK_XEVENT = xlenter("CALLBACK_XEVENT"); /* wc_*.c */
  643. #ifdef WINTERP_MOTIF_11
  644.   s_CALLBACK_CLICK_COUNT = xlenter("CALLBACK_CLICK_COUNT"); /* wc_ArrowB.c wc_DrawnB.c wc_PushB.c */
  645. #endif                /* WINTERP_MOTIF_11 */
  646.   s_CALLBACK_WINDOW = xlenter("CALLBACK_WINDOW"); /* wc_DrawingA.c wc_DrawnB.c */
  647.   s_CALLBACK_VALUE = xlenter("CALLBACK_VALUE");    /* wc_Command.c wc_FileSB.c wc_Scale.c wc_ScrollBar.c wc_SelectioB.c */
  648.   s_CALLBACK_LENGTH = xlenter("CALLBACK_LENGTH"); /* wc_Command.c wc_FileSB.c wc_SelectioB.c */
  649.  
  650.   s_CR_NONE = xlenter("CR_NONE");
  651.   s_CR_HELP = xlenter("CR_HELP");
  652.   s_CR_VALUE_CHANGED = xlenter("CR_VALUE_CHANGED");
  653.   s_CR_INCREMENT = xlenter("CR_INCREMENT");
  654.   s_CR_DECREMENT = xlenter("CR_DECREMENT");
  655.   s_CR_PAGE_INCREMENT = xlenter("CR_PAGE_INCREMENT");
  656.   s_CR_PAGE_DECREMENT = xlenter("CR_PAGE_DECREMENT");
  657.   s_CR_TO_TOP = xlenter("CR_TO_TOP");
  658.   s_CR_TO_BOTTOM = xlenter("CR_TO_BOTTOM");
  659.   s_CR_DRAG = xlenter("CR_DRAG");
  660.   s_CR_ACTIVATE = xlenter("CR_ACTIVATE");
  661.   s_CR_ARM = xlenter("CR_ARM");
  662.   s_CR_DISARM = xlenter("CR_DISARM");
  663.   s_CR_MAP = xlenter("CR_MAP");
  664.   s_CR_UNMAP = xlenter("CR_UNMAP");
  665.   s_CR_FOCUS = xlenter("CR_FOCUS");
  666.   s_CR_LOSING_FOCUS = xlenter("CR_LOSING_FOCUS");
  667.   s_CR_MODIFYING_TEXT_VALUE = xlenter("CR_MODIFYING_TEXT_VALUE");
  668.   s_CR_MOVING_INSERT_CURSOR = xlenter("CR_MOVING_INSERT_CURSOR");
  669.   s_CR_EXECUTE = xlenter("CR_EXECUTE");
  670.   s_CR_SINGLE_SELECT = xlenter("CR_SINGLE_SELECT");
  671.   s_CR_MULTIPLE_SELECT = xlenter("CR_MULTIPLE_SELECT");
  672.   s_CR_EXTENDED_SELECT = xlenter("CR_EXTENDED_SELECT");
  673.   s_CR_BROWSE_SELECT = xlenter("CR_BROWSE_SELECT");
  674.   s_CR_DEFAULT_ACTION = xlenter("CR_DEFAULT_ACTION");
  675.   s_CR_CLIPBOARD_DATA_REQUEST = xlenter("CR_CLIPBOARD_DATA_REQUEST");
  676.   s_CR_CLIPBOARD_DATA_DELETE = xlenter("CR_CLIPBOARD_DATA_DELETE");
  677.   s_CR_CASCADING = xlenter("CR_CASCADING");
  678.   s_CR_OK = xlenter("CR_OK");
  679.   s_CR_CANCEL = xlenter("CR_CANCEL");
  680.   s_CR_APPLY = xlenter("CR_APPLY");
  681.   s_CR_NO_MATCH = xlenter("CR_NO_MATCH");
  682.   s_CR_COMMAND_ENTERED = xlenter("CR_COMMAND_ENTERED");
  683.   s_CR_COMMAND_CHANGED = xlenter("CR_COMMAND_CHANGED");
  684.   s_CR_EXPOSE = xlenter("CR_EXPOSE");
  685.   s_CR_RESIZE = xlenter("CR_RESIZE");
  686.   s_CR_INPUT = xlenter("CR_INPUT");
  687. #ifdef WINTERP_MOTIF_11
  688.   s_CR_GAIN_PRIMARY = xlenter("CR_GAIN_PRIMARY");
  689.   s_CR_LOSE_PRIMARY = xlenter("CR_LOSE_PRIMARY");
  690. #ifdef XmCR_CREATE        /* added in Motif 1.1.3 */
  691.   s_XmCR_CREATE = xlenter("CR_CREATE");
  692. #endif /* XmCR_CREATE */
  693. #ifdef XmCR_PROTOCOLS        /* added in Motif 1.1.3 */
  694.   s_XmCR_PROTOCOLS = xlenter("CR_PROTOCOLS");
  695. #endif /* XmCR_PROTOCOLS */
  696. #endif                /* WINTERP_MOTIF_11 */
  697.  
  698. #ifdef HP_GRAPH_WIDGET
  699.   s_CR_NEW_ARC = xlenter("CR_NEW_ARC");
  700.   s_CR_NEW_NODE = xlenter("CR_NEW_NODE");
  701.   s_CR_NODE_MOVED = xlenter("CR_NODE_MOVED");
  702.   s_CR_ARC_MOVED = xlenter("CR_ARC_MOVED");
  703.   s_CR_SUBGRAPH_MOVED = xlenter("CR_SUBGRAPH_MOVED");
  704.   s_CR_ARC_EDITED = xlenter("CR_ARC_EDITED");
  705.   s_CR_SELECT_NODE = xlenter("CR_SELECT_NODE");
  706.   s_CR_SELECT_ARC = xlenter("CR_SELECT_ARC");
  707.   s_CR_SELECT_SUBGRAPH = xlenter("CR_SELECT_SUBGRAPH");
  708.   s_CR_DELETE_NODE = xlenter("CR_DELETE_NODE");
  709.   s_CR_DELETE_ARC = xlenter("CR_DELETE_ARC");
  710.   s_CR_SELECT= xlenter("CR_SELECT");
  711.   s_CR_RELEASE= xlenter("CR_RELEASE");
  712.   s_CR_NODE_DOUBLE_CLICK= xlenter("CR_NODE_DOUBLE_CLICK");
  713.   s_CR_ARC_DOUBLE_CLICK= xlenter("CR_ARC_DOUBLE_CLICK");
  714.   s_CR_DOUBLE_CLICK= xlenter("CR_DOUBLE_CLICK");
  715.   s_CR_DESELECT_NODE = xlenter("CR_DESELECT_NODE");
  716.   s_CR_DESELECT_ARC = xlenter("CR_DESELECT_ARC");
  717.   s_CR_DESELECT = xlenter("CR_DESELECT");
  718. #endif                /* HP_GRAPH_WIDGET */
  719.  
  720.   s_CALLBACK_NO_LIST = xlenter("CALLBACK_NO_LIST");
  721.   s_CALLBACK_HAS_NONE = xlenter("CALLBACK_HAS_NONE");
  722.   s_CALLBACK_HAS_SOME = xlenter("CALLBACK_HAS_SOME");
  723. }
  724.